﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace SqliteDriver
{
	public class SqliteOptionInterfaceImplementations : DbViewDriver.ISchemaInfo, DbViewDriver.ILookup
	{
		SqliteDataSource datasource;
		private List<DbView.FieldInfo> fields {get; set;}
		private string table="";

		public SqliteOptionInterfaceImplementations(SqliteDataSource ds)
		{
			this.datasource = ds;
		}
		//////////////////////////////////////////////////////
		// 
		public string ConnectionString
		{
			get
			{
				return datasource.ConnectionString;
			}
		}

		public DbView.FieldInfo[] GetSchema(string tableName)
		{
			if (this.fields == null || tableName != table)  // cache not valid condition
			{
				SqlTableSchema schema = Helper.MakeSchemaFor(tableName, this.ConnectionString);
				fields = new List<DbView.FieldInfo>();
				for (int idx = 0; idx < schema.Count; ++idx)
					fields.Add(schema[idx]);
			}
			return this.fields.ToArray();
		}
		////////////////////////////////////////////////////////////////////////////////
		// Hacky hack hack for execution speed on large databases.
		// given an array of tables return a map of table to arrays of the field info that matters.
		//
		public Dictionary<string, DbView.FieldInfo[]> GetBasicSchemas(string[] tableNames)
		{
			Dictionary<string, DbView.FieldInfo[]> map = new Dictionary<string,DbView.FieldInfo[]>();
			foreach (string tableName in tableNames)
			{
				SqlTableSchema schema = this.datasource.MakeSchemaFor(tableName);
				map.Add(tableName, schema.Fields);
			}
			return map;
		}

		String DataFromCell(DataRow dr, String columnName)
		{
			if (!dr.Table.Columns.Contains(columnName)) return "";
			return dr[columnName].ToString();
		}

		bool TfFromData(String data)
		{
			if (data.Length == 0) return false;  // empty means no
			char c = data[0];
			if (c == 'Y' || c == 'y' || c == 'T' || c == 't') return true;
			if (c == '1') return true;
			if (c == '0') return true;
			// Unless N or No then true
			if ((c == 'N' || c == 'n') && data.Length <= 2) return false;
			// handle other cases as they arise
			return true;
		}
		//////////////////////////////////////////////////////////////////

		public string[] GetTables()
		{
			// there is no filter
			string tableNameFilter = "";
			// get the short-form template for tables as this just needs names

			string template = SqliteTemplates.Templates.FetchTemplate(3, DbView.Commands.Cmnd.Tables);
			string sql = SqliteTemplates.Templates.ProcessFilterClause(template, tableNameFilter);
			DataTable dt = Helper.GenericQuery(ConnectionString, sql, "TABLES");
			List<string> tables = new List<string>();
			foreach (DataRow dr in dt.Rows)
			{
				tables.Add(dr[0].ToString());
			}
			return tables.ToArray();
		}

		public System.Data.DataTable GetFkInfo()
		{
			// get the standard FK template as it will do. (Cunning/oblique design!)
			string template = SqliteTemplates.Templates.FetchTemplate(this.datasource.SqlVersion, DbView.Commands.Cmnd.ForeignKeys);
			// have to resolve the fancy lookup text
			string sql = SqliteTemplates.Templates.ProcessFilterClause(template, "");
			DataTable tableDt = Helper.GenericQuery(ConnectionString, sql, "FK");
			// for sqlite this is just a list of tables. There is more to do
			DataTable dt = TableCommandProcessor.GetTableFKInfo(ConnectionString, tableDt);
			return dt;
		}

		//////////////////////////////////////////////////////
		// 
		public DbViewDriver.ISchemaInfo GetSchemaInfo()
		{
			return this as DbViewDriver.ISchemaInfo;
		}

		public string BuildLookupCommand(string pkTable, string[] pkFields, string keyField, string lookupData)
		{
			string template = @"select [{0}] from {1} where {2} in ({3})";
			string fieldList = string.Join("],[",pkFields);
			string command = string.Format(template, fieldList, Helper.SafeTableName(pkTable), Helper.SafeSqlField(keyField), lookupData);
			// order by clause
			if (lookupData.Contains(",") )
			{
				string[] items = lookupData.Split(',');
				if (items.Length < 40)  // magic number. OrderBy threshold. More than this its not worth bothering with.
				{
					// but don't kill the sql engine
					string clause = "";
					for (int idx = 0; idx < items.Length; ++idx)
					{
						clause += string.Format("when {0} then {1} ", items[idx], idx);
					}
					string orderBy = string.Format(" order by case {0} {1} end", Helper.SafeSqlField(keyField), clause);
					command += orderBy;
				}
			}
			return command;
		}
	}
}
